/*-------------------------------------------------------------------------
 *
 * condition_variable.h
 *	  条件变量
 *
 * 条件变量是一种等待特定条件变为真的方法. 传统上，条件变量支持三种
 * 操作: (1) sleep; (2) signal，唤醒在条件变量上睡眠的一个进程; 以及 (3) broadcast，
 * 唤醒在条件变量上睡眠的所有进程. 在我们的实现中，条件变量将进程置于可中断的
 * 睡眠状态（因此它可以在条件满足之前被取消），并且不在内部使用指针（因此它们
 * 可以安全地在 DSM 中使用）。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/storage/condition_variable.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef CONDITION_VARIABLE_H
#define CONDITION_VARIABLE_H

#include "storage/proclist_types.h"
#include "storage/spin.h"

typedef struct
{
	slock_t		mutex;			/* 保护唤醒列表的自旋锁 */
	proclist_head wakeup;		/* 可唤醒进程列表 */
} ConditionVariable;

/*
 * 将条件变量填充为二的幂次大小，以便条件变量数组不跨越缓存行边界。
 */
#define CV_MINIMAL_SIZE		(sizeof(ConditionVariable) <= 16 ? 16 : 32)
typedef union ConditionVariableMinimallyPadded
{
	ConditionVariable cv;
	char		pad[CV_MINIMAL_SIZE];
} ConditionVariableMinimallyPadded;

/* 初始化条件变量。 */
extern void ConditionVariableInit(ConditionVariable *cv);

/*
 * 要在条件变量上休眠，进程应使用一个循环，首先
 * 检查条件，如果满足条件则退出循环，然后调用
 * ConditionVariableSleep。可能会发生虚假唤醒，但
 * 应该不频繁。在退出循环后，必须调用
 * ConditionVariableCancelSleep，以确保进程不再
 * 在条件变量的等待列表中。
 */
extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info);
extern bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout,
										uint32 wait_event_info);
extern void ConditionVariableCancelSleep(void);

/*
 * 可选择地，在进入上述测试和休眠循环之前可以调用
 * ConditionVariablePrepareToSleep。如果需要至少一次休眠，
 * 这样做更有效，而如果不需要休眠，因为第一次测试条件为真，
 * 不这样做更有效。
 */
extern void ConditionVariablePrepareToSleep(ConditionVariable *cv);

/* 唤醒一个等待者（通过信号）或所有等待者（通过广播）。 */
extern void ConditionVariableSignal(ConditionVariable *cv);
extern void ConditionVariableBroadcast(ConditionVariable *cv);

#endif							/* CONDITION_VARIABLE_H */
